package com.kx.smsolatform.service.impl;

import com.kx.smsolatform.pojo.SearchPojo;
import com.kx.smsolatform.service.SearcherService;
import com.kx.smsolatform.util.JsonUtils;
import com.kx.smsplatform.common.enums.InterfaceExceptionEnums;
import com.kx.smsplatform.common.exception.SmsException;
import com.kx.smsplatform.common.model.StandardReport;
import com.kx.smsplatform.common.model.StandardSubmit;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author Sun
 * @Date 2021/7/6 17:43
 */
@Slf4j
@Service
public class SearcherServiceImpl implements SearcherService {

    @Autowired
    private RestHighLevelClient client;

    @Override
    public void addLog(StandardSubmit submit) throws IOException {
        //1.创建request对象
        IndexRequest request = new IndexRequest();

        //2.将数据封装到request对象中
        String index = "sms_submit_log_2021";
        request.index(index);//设置索引
        if (!StringUtils.isEmpty(submit.getSequenceId())) {
            String id = submit.getSequenceId();
            request.id(id);  // 设置id
        }
        request.source(JsonUtils.objectToMap(submit));
        //3.发送给es
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        //4.根据返回结果判断是否成功
        if (!"CREATED".equals(response.getResult().toString())) {
            log.error("【搜索模块: 添加数据】添加数据失败！！, index = {},submit = {}", index, submit);
            throw new SmsException(InterfaceExceptionEnums.SEARCH_SAVE_LOG_ERROR);
        }
    }

    @Override
    public void updateLog(StandardReport report) throws IOException {
        //更新日志信息,将state和errorCode字段根据具体的状态进行更新
        //1.创建updateRequest对象
        UpdateRequest updateRequest = new UpdateRequest();
        //2.封装数据
        String index = "sms_submit_log_2021";
        updateRequest.index(index);//设置索引
        updateRequest.id(report.getSequenceId());//设置id
        HashMap<String, Object> source = new HashMap<>();
        source.put("reportState", report.getState() + "");
        source.put("errorCode", report.getErrorCode());

        updateRequest.doc(source);
        //3.将数据发送给es
        UpdateResponse update = client.update(updateRequest, RequestOptions.DEFAULT);
        //4.根据返回结果进行判断是否成功
        String s = update.getResult().toString();
        if (!"UPDATED".equals(s)) {
            log.error("【搜索模块: 更新数据】更新数据失败!!, index = {},report = {}", index, report);
            throw new SmsException(InterfaceExceptionEnums.SEARCH_UPDATE_LOG_ERROR);
        }

    }

    @Override
    public List<Map> searchLog(String paras) throws IOException {
        SearchResponse searchResponse = this.searchCommon(paras);
        //拿到所有查询的数据
        SearchHit[] hits = searchResponse.getHits().getHits();
        List<Map> list = new ArrayList<>();
        for (SearchHit hit : hits) {
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            //获取所有高亮字段
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            //获取短信内容高亮
            HighlightField messageContent = highlightFields.get("messageContent");
            //说明有高亮
            if (messageContent != null) {
                sourceAsMap.put("messageContent", messageContent.getFragments()[0].toString());
            }
            list.add(sourceAsMap);
        }
        return list;
    }

    @Override
    public Long searchLogCount(String paras) throws IOException {
        //根据条件获取总条数
        SearchResponse searchResponse = this.searchCommon(paras);
        return searchResponse.getHits().getTotalHits().value;
    }

    @Override
    public Map<String, Long> statSendStatus(String paras) throws IOException {
        //查询状态信息，成功0、失败2、发送中1

        SearchPojo searchPojo = JsonUtils.json2Object(paras, SearchPojo.class);
        log.info("【搜索模块 统计报表】搜索条件为:{}", searchPojo);
        //1.创建SearchRequest对象
        SearchRequest searchRequest = new SearchRequest();
        //2.封装数据
        searchRequest.indices("sms_submit_log_2021");//设置索引
        //使用查询条件(BoolQuery)
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //2.1校验每个查询条件,根据条件进行查询

        //开始时间
        if (searchPojo.getStartTime() != null) {
            String startTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(searchPojo.getStartTime());
            boolQuery.must(QueryBuilders.rangeQuery("sendTime").gte(startTimeFormat));
        }

        //结束时间
        if (searchPojo.getEndTime() != null) {
            String endTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(searchPojo.getEndTime());
            boolQuery.must(QueryBuilders.rangeQuery("sendTime").lte(endTimeFormat));
        }

        //公司id
        if (searchPojo.getClientID() != null) {
            boolQuery.must(QueryBuilders.termQuery("clientID", searchPojo.getClientID()));
        }

        //2.2将数据封装到sourceBuilder中
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //使用聚合函数terms查询
        sourceBuilder.query(boolQuery);
        sourceBuilder.aggregation(AggregationBuilders.terms("status").field("reportState"));

        //2.3封装到request对象中
        searchRequest.source(sourceBuilder);

        //3.发送请求获取response对象
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

        //向下转型
        Terms states = searchResponse.getAggregations().get("status");
        Map<String, Long> map = new HashMap<>();
        for (Terms.Bucket statesBucket : states.getBuckets()) {
            //成功0、发送中1、失败2
            map.put(statesBucket.getKeyAsString(), statesBucket.getDocCount());
        }
        return map;
    }

    /**
     * 封装查询条件,便于每次进行调用
     */
    public SearchResponse searchCommon(String paras) throws IOException {

        SearchPojo searchPojo = JsonUtils.json2Object(paras, SearchPojo.class);
        log.info("【搜索模块 短信查询】搜索条件为:{}", searchPojo);
        //1.创建SearchRequest对象
        SearchRequest searchRequest = new SearchRequest();
        //2.封装数据
        searchRequest.indices("sms_submit_log_2021");//设置索引
        //使用查询条件(BoolQuery)
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //2.1校验每个查询条件,根据条件进行查询

        //关键字,一个关键字匹配多个字段
        if (!StringUtils.isEmpty(searchPojo.getKeyword())) {

            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(searchPojo.getKeyword(), "errorCode", "msgid", "reportErrorCode", "messageContent");
            boolQuery.must(multiMatchQueryBuilder);
        }

        //手机号
        if (!StringUtils.isEmpty(searchPojo.getMobile())) {
            boolQuery.must(QueryBuilders.termQuery("destMobile", searchPojo.getMobile()));
        }

        //开始时间
        if (searchPojo.getStartTime() != null) {
            String startTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(searchPojo.getStartTime());
            boolQuery.must(QueryBuilders.rangeQuery("sendTime").gte(startTimeFormat));
        }

        //结束时间
        if (searchPojo.getEndTime() != null) {
            String endTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(searchPojo.getEndTime());
            boolQuery.must(QueryBuilders.rangeQuery("sendTime").lte(endTimeFormat));
        }

        //公司id
        if (searchPojo.getClientID() != null) {
            boolQuery.must(QueryBuilders.termQuery("clientID", searchPojo.getClientID()));
        }
        //2.2将数据封装到sourceBuilder中
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(boolQuery);

        //2.3设置分页信息
        sourceBuilder.from(searchPojo.getStart());
        sourceBuilder.size(searchPojo.getRows());

        //2.4高亮查询,短信内容高亮显示
        if (!StringUtils.isEmpty(searchPojo.getKeyword())) {
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("messageContent");
            highlightBuilder.fragmentSize(100);
            highlightBuilder.preTags(searchPojo.getHighLightPreTag());
            highlightBuilder.postTags(searchPojo.getHighLightPostTag());
            sourceBuilder.highlighter(highlightBuilder);
        }

        //2.5封装到request对象中
        searchRequest.source(sourceBuilder);

        //3.发送请求获取response对象
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        return searchResponse;
    }

}
